package com.cy.pj.sys.service.impl;

import com.cy.pj.common.annotation.RequiredLog;
import com.cy.pj.common.exception.ServiceException;
import com.cy.pj.common.vo.PageObject;
import com.cy.pj.common.vo.SysUserDeptVo;
import com.cy.pj.sys.dao.SysUserDao;
import com.cy.pj.sys.dao.SysUserRoleDao;
import com.cy.pj.sys.pojo.SysUser;
import com.cy.pj.sys.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * @Author YuBaoFu
 * @create 2025/06/04
 * @description
 */
@Service
@Slf4j
@Transactional(
        timeout = 30,
        readOnly = false,
        isolation = Isolation.READ_COMMITTED,
        rollbackFor = Throwable.class,
        propagation = Propagation.REQUIRED,
        noRollbackFor = ServiceException.class
)
public class SysUserServiceImpl implements SysUserService {

    @Autowired
    private SysUserDao sysUserDao;

    @Autowired
    private SysUserRoleDao sysUserRoleDao;


    @RequiredLog(operation = "查询用户信息")
    @Override
    @Transactional(readOnly = true)
    public PageObject<SysUserDeptVo> findPageObjects(String username, Integer pageCurrent) {
        //1.对参数进行校验
        if(pageCurrent==null||pageCurrent<1)
            throw new IllegalArgumentException("当前页码值无效");
        //2.查询总记录数并进行校验
        int rowCount=sysUserDao.getRowCount(username);
        if(rowCount==0)
            throw new ServiceException("没有找到对应记录");
        //3.查询当前页记录
        int pageSize=2;
        int startIndex=(pageCurrent-1)*pageSize;
        List<SysUserDeptVo> records=
                sysUserDao.findPageObjects(username,startIndex, pageSize);
        //4.对查询结果进行封装并返回
        return new PageObject<>(pageCurrent, pageSize, rowCount, records);
    }

    /**
     * RequiresPermissions 注解由shiro框架提供，此注解描述的方法为切入点方法，
     * 表示在方法执行时，需要进行授权，也就是说假如用户拥有此方法访问的权限，才
     * 可以访问这个方法。
     * @param id
     * @param valid
     * @return
     */
    @RequiredLog(operation = "操作用户状态")
    @Override
    @RequiresPermissions("sys:user:update")
    public int validById(Integer id, Integer valid) {
        //1.合法性验证
        if(id==null||id<=0)
            throw new ServiceException("参数不合法,id="+id);
        if(valid!=1&&valid!=0)
            throw new ServiceException("参数不合法,valid="+valid);
        //                if(StringUtils.isEmpty(modifiedUser))
        //                throw new ServiceException("修改用户不能为空");
        //2.执行禁用或启用操作(admin为后续登陆用户）
        int rows=sysUserDao.validById(id, valid,"admin");
        //3.判定结果,并返回
        if(rows==0)
            throw new ServiceException("此记录可能已经不存在");
        return rows;
    }

    @Override
    public int saveObject(SysUser sysUser, Integer[] roleIds) {
        long start = System.currentTimeMillis();
        log.info("开始时间 => " + start);
        /*参数合法校验*/
        if (sysUser == null) {
            throw new ServiceException("保存用户信息不可为空");
        }
        if (StringUtils.isEmpty(sysUser.getUsername())){
            throw new ServiceException("保存用户姓名不可为空");
        }
        if (StringUtils.isEmpty(sysUser.getPassword())){
            throw new ServiceException("保存用户密码不可为空");
        }
        if (roleIds==null || roleIds.length < 1){
            throw new ServiceException("保存用户必须分配角色");
        }
//        获取密码 生成盐值
        String source = sysUser.getPassword();
        String salt = UUID.randomUUID().toString();
        /* 根据盐值和算法 加密密码 */
        SimpleHash simpleHash = new SimpleHash("MD5",
                source,salt,1);
        sysUser.setSalt(salt);
        sysUser.setPassword(simpleHash.toHex());
        sysUser.setCreatedUser("王鹏力");
        sysUser.setModifiedUser("王鹏力");
        /*新增用户*/
        int rows = sysUserDao.insertObject(sysUser);
        if (rows == 0){
            throw new ServiceException("保存用户失败，请联系管理员重试");
        }
        /*新增用户成功之后 增加关联表内容*/
        sysUserRoleDao.insertObjects(sysUser.getId(),roleIds);
        long end = System.currentTimeMillis();
        log.info("结束时间 => " + end);
        log.info("新增用时 => " + (end-start));
        return rows;
    }

    @Override
    public Map<String, Object> findObjectById(Integer userId) {
        //1.合法性验证
        if(userId==null||userId<=0)
            throw new IllegalArgumentException("参数数据不合法,userId="+userId);
        //2.业务查询
        SysUserDeptVo sysUserDeptVo=sysUserDao.findObjectById(userId);
        if(sysUserDeptVo==null)
            throw new ServiceException("此用户已经不存在");
        List<Integer> roleIds=sysUserRoleDao.findRoleIdsByUserId(userId);
        //3.数据封装
        Map<String,Object> map=new HashMap<>();
        map.put("user", sysUserDeptVo);
        map.put("roleIds", roleIds);
        return map;
    }

    @Override
    public int updateObject(SysUser sysUser,Integer[] roleIds) {
        //1.参数有效性验证
        if(sysUser==null)
            throw new IllegalArgumentException("保存对象不能为空");
        if(sysUser.getId() == null || sysUser.getId() < 1){
            throw new IllegalArgumentException("修改用户的ID不合法，id= " + sysUser.getId());
        }
        if(StringUtils.isEmpty(sysUser.getUsername()))
            throw new IllegalArgumentException("用户名不能为空");
        if(roleIds==null||roleIds.length==0)
            throw new IllegalArgumentException("必须为其指定角色");

        //其它验证自己实现，例如用户名已经存在，密码长度，...
        //2.更新用户自身信息
        int rows=sysUserDao.updateObject(sysUser);
        if(rows == 0){
            throw new ServiceException("此用户可能已经不存在");
        }
        //3.保存用户与角色关系数据
        sysUserRoleDao.deleteObjectsByUserId(sysUser.getId());
        sysUserRoleDao.insertObjects(sysUser.getId(), roleIds);
        //4.返回结果
        return rows;
    }
}
